// PHZ
// 2018-5-15

#ifndef XOP_CHANNEL_H
#define XOP_CHANNEL_H

#include <functional>
#include <memory>
#include "Socket.h"

namespace xop {

enum EventType: uint32_t {
	EVENT_NONE = 0,
	EVENT_IN = 1,
	EVENT_PRI = 2,
	EVENT_OUT = 4,
	EVENT_ERR = 8,
	EVENT_HUP = 16,
	EVENT_RDHUP = 8192
};

class Channel {
public:
	typedef std::function<void()> EventCallback;

	Channel() = delete;

	explicit Channel(const SOCKET sockfd) : sockfd_(sockfd) {}

	virtual ~Channel() = default;

	void SetReadCallback(const EventCallback &cb) { read_callback_ = cb; }

	void SetWriteCallback(const EventCallback &cb) { write_callback_ = cb; }

	void SetCloseCallback(const EventCallback &cb) { close_callback_ = cb; }

	void SetErrorCallback(const EventCallback &cb) { error_callback_ = cb; }

	SOCKET GetSocket() const { return sockfd_; }

	uint32_t GetEvents() const { return events_; }
	void SetEvents(const int events) { events_ = events; }

	void EnableReading() { events_ |= EVENT_IN; }

	void EnableWriting() { events_ |= EVENT_OUT; }

	void DisableReading() { events_ &= ~EVENT_IN; }

	void DisableWriting() { events_ &= ~EVENT_OUT; }

	bool IsNoneEvent() const { return events_ == EVENT_NONE; }
	bool IsWriting() const { return (events_ & EVENT_OUT) != 0; }
	bool IsReading() const { return (events_ & EVENT_IN) != 0; }

	void HandleEvent(const uint32_t events) const
	{
		if (events & (EVENT_PRI | EVENT_IN)) {
			read_callback_();
		}

		if (events & EVENT_OUT) {
			write_callback_();
		}

		if (events & EVENT_HUP) {
			close_callback_();
			return;
		}

		if (events & EVENT_ERR) {
			error_callback_();
		}
	}

private:
	EventCallback read_callback_ = [] {};
	EventCallback write_callback_ = [] {};
	EventCallback close_callback_ = [] {};
	EventCallback error_callback_ = [] {};

	SOCKET sockfd_ = 0;
	uint32_t events_ = 0;
};

typedef std::shared_ptr<Channel> ChannelPtr;

}

#endif
